/* 
 Backup folder copy
 Version 3
 By Ben a.k.a DreamVB
*/

#include <iostream>
#include <Windows.h>
#include <string>
#include <algorithm>

using namespace std;
using std::cout;
using std::endl;

int Copyed = 0;
int Skipped = 0;

string LCase(string src)
{
	string Temp = src;
	std::transform(Temp.begin(), Temp.end(), Temp.begin(), ::tolower);
	return Temp;
}

string FixPath(string src){
	if (src[src.length() - 1] != '\\'){
		return src + "\\";
	}
	return src;
}

bool DirExists(string filename){
	if ((GetFileAttributesA(filename.c_str()) != FILE_ATTRIBUTE_DIRECTORY)){
		return false;
	}
	return true;
}

void MyCreateDir(string PathName){
	int i = 0;
	int j = 0;
	string sPart = "";
	string sDir = "";

	//Append end backslash.
	if (!PathName[PathName.length() - 1] != '\\'){
		PathName += "\\";
	}

	while (i < PathName.length()){
		if (PathName[i] == '\\'){
			//The path to create
			sDir += sPart + "\\";
			//Check for folder.
			if ((GetFileAttributesA(sDir.c_str()) & FILE_ATTRIBUTE_DIRECTORY)){
				//Create folder
				CreateDirectoryA(sDir.c_str(), NULL);
			}
			//Clear parts.
			sPart.clear();
		}
		else{
			//Split the string by backslash
			sPart += PathName[i];
		}
		//INC counter
		i++;
	}
	sPart.clear();
	sDir.clear();
}

void DirTree(string Path, string lzDestPath, string FileType, bool AllDirs){
	HANDLE f = 0;
	WIN32_FIND_DATAA wfd;

	string lzPath = "";
	string lzCopyTo = "";
	string NewPath = "";
	string lzSrcFile = "";
	string lzDestFile = "";
	string Temp = "";
	string fExt = "";
	int pos = string::npos;

	//Append backslash to path.
	lzPath = FixPath(Path);

	//Find first file.
	f = FindFirstFileA((lzPath + "*.*").c_str(), &wfd);

	//Check for inaild path.
	if (f == INVALID_HANDLE_VALUE){
		cout << "Folder or files not found." << endl << lzPath.c_str() << endl;
		FindClose(f);
		exit(1);
	}

	//Gets the list of files
	do{
		if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
			//Build file path

			if (wfd.cFileName[0] != 46){
				NewPath = FixPath(lzPath + wfd.cFileName);

				//Scan all sub folders.
				if (AllDirs){
					if (DirExists(NewPath)){
						DirTree(NewPath, lzDestPath, FileType, AllDirs);
					}
				}
			}

		}
		else{
			if (FileType.length() != 0){
				fExt = LCase(wfd.cFileName);
				pos = fExt.find_last_of('.');
				if (pos != string::npos){
					fExt.erase(0, pos);
					if (fExt == FileType){
						//Set src filename
						lzSrcFile = lzPath + wfd.cFileName;
					}
				}
			}
			else{
				//Set src filename
				lzSrcFile = lzPath + wfd.cFileName;
			}
			//Test if we have a filename.
			if (lzSrcFile.length() != 0){
				//Set dest filename
				Temp = lzSrcFile;
				pos = Temp.find_first_of('\\');
				if (pos != string::npos){
					Temp.erase(0, pos + 1);
				}

				//Set dest filename
				lzDestFile = lzDestPath + Temp;
				//Extract the dest full path.
				pos = lzDestFile.find_last_of('\\');
				if (pos != string::npos){
					lzCopyTo = lzDestFile.substr(0, pos);
				}

				//Create destination folders
				if (!DirExists(lzCopyTo)){
					MyCreateDir(lzCopyTo);
				}

				//Copy the src file over to the folder.
				if (!CopyFileA(lzSrcFile.c_str(), lzDestFile.c_str(), false)) {
					cout << lzDestFile.c_str() << "....Skipped" << endl;
					Skipped++;
				}
				else{
					cout << lzDestFile.c_str() << "....OK" << endl;
					Copyed++;
				}

				lzSrcFile.clear();
				Temp.clear();
			}

		}
	} while (FindNextFileA(f, &wfd) != 0);

	//Close file
	FindClose(f);
}

int main(int argc, char *argv[]){
	string Temp = "";
	string DeskFolder = "";
	string fExt = "";
	string Flags = "";
	bool ScanAllDirs = false;
	int pos = string::npos;
	int i = 3;

	//Check for help switch
	if (argc == 2){
		Flags = argv[1];
		//If help switch display online help
		if (Flags == "/?"){
			cout << "Backup Folders version 3.1" << endl << endl;
			cout << argv[0] << " <source> <destination> [/S]" << endl << endl;
			cout << " source         specifies the folder with the file(s) to copy." << endl;
			cout << " destination    specifies were the file(s) should be copyed to." << endl;
			cout << " /S             When set all sub folders are included in backup." << endl;
			cout << endl;
			exit(1);
		}
		exit(1);
	}

	//Check argv
	if (argc < 3){
		cout << "Usage: " << argv[0] << " <source> <destination> [options]" << endl << endl;
		cout << "For more information see " << argv[0] << " /?" << endl;
		exit(1);
	}

	//Get other args
	while (i < argc){
		Flags = LCase(argv[i]);

		if (Flags == "/s"){
			ScanAllDirs = true;
		}
		//INC counter
		i++;
	}

	//Source folder
	Temp = argv[1];
	//Destination folder
	DeskFolder = FixPath(argv[2]);

	pos = Temp.find('*');

	if (pos != string::npos){
		fExt = LCase(Temp.substr(pos + 1));
		if (fExt == ".*"){
			fExt = "";
		}
		//Fix the path
		Temp.erase(pos);
	}

	//Place on folder path as title.
	cout << "Folder Listing For " << Temp.c_str() << endl << endl;
	//Call DirTree procedure
	DirTree(Temp, DeskFolder, fExt, ScanAllDirs);
	//Display results
	cout << endl;
	cout << "Copyed  : " << Copyed << endl;
	cout << "Skipped : " << Skipped << endl;

	return EXIT_SUCCESS;
}

